package com.demo.log;

import java.time.Duration;
import java.time.LocalDateTime;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import com.demo.util.CommonContrants;
import com.demo.util.JacksonJsonUtils;

import lombok.extern.slf4j.Slf4j;

/**
 * 通过切面 记录请求日志
 *
 */
@Slf4j
@Aspect
@Component
public class LogAspect {

    @Around("@within(org.springframework.web.bind.annotation.RestController)")
    public Object doAroundLog(ProceedingJoinPoint thisJoinPoint) throws Throwable {
        Object r = null;
        String method = thisJoinPoint.getSignature().getName();
        LocalDateTime startTime = LocalDateTime.now();
        String traceId = "";
        String url = null;
        Map<String, Object> param = null;
        boolean flag = false;
        try {
            ServletRequestAttributes requestAttributes =
                (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = requestAttributes.getRequest();
            url = request.getRequestURL().toString();
            traceId = (String)request.getAttribute(CommonContrants.HEADER_TRACE_ID);
            param = getArgs(thisJoinPoint, ((MethodSignature)thisJoinPoint.getSignature()).getParameterNames());
            param.put(CommonContrants.HEADER_SIGNATURE, request.getHeader(CommonContrants.HEADER_SIGNATURE));
           

            r = thisJoinPoint.proceed();// 被代理对象执行结果
        } catch (Throwable e) {
            flag = true;
            throw e;// 异常信息有统一异常处理器处理
        } finally {
            log.info("[trace-id:{}] [方法:{}]  [访问地址:{}] [执行时间：{}(豪秒)]  [参数:{}] [结果:{}]", traceId,
                (thisJoinPoint.getTarget().getClass().getSimpleName() + "." + method), url,
                Duration.between(startTime, LocalDateTime.now()).toMillis(), param, flag ? "异常" : "正常");
        }
        return r;
    }

    private Map<String, Object> getArgs(ProceedingJoinPoint joinPoint, String[] parameterNames) {
        Map<String, Object> allArgs = new HashMap<>();
        Object[] args = joinPoint.getArgs();
        for (int k = 0; k < args.length; k++) {
            Object arg = args[k];
            if (arg == null || arg instanceof ServletResponse || arg instanceof ServletRequest) {
                
            } else if (arg instanceof MultipartFile) {// 文件
                allArgs.put(parameterNames[k], ((MultipartFile)arg).getOriginalFilename());
            } else if (arg instanceof MultipartFile[]) {// 文件
                allArgs.put(parameterNames[k], ((MultipartFile[])arg).length);
            } else if (arg instanceof Number || arg instanceof String || arg instanceof Character
                || arg instanceof Boolean) {// 简单类型
                allArgs.put(parameterNames[k], arg);
            } else if (arg instanceof Collection) {// 集合
                allArgs.put(parameterNames[k], arg);
            } else if (arg.getClass().isArray()) {// 数组
                allArgs.put(parameterNames[k],
                    JacksonJsonUtils.readObject(JacksonJsonUtils.writeObject(arg), List.class));
            } else {// 复杂类型
                Map<String, Object> m = JacksonJsonUtils.convertToMap(arg);
                if (m != null) {
                    allArgs.putAll(m);
                }
            }
        }
        return allArgs;
    }
}
